From 89e3cdb01f2bf01810474984fd2c676a88973ac5 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 13 Oct 2017 14:38:37 +0200
Subject: [PATCH 15/36] clk: meson: gxbb: Add VPU and VAPB clocks data

The Amlogic Meson GX SoCs needs these two clocks to power up the
VPU power domain.

These two clocks are similar to the MALI clocks by having a glitch-free
mux and two similar clocks with gate, divider and muxes.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/clk/meson/gxbb.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 292 insertions(+)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index b2d1e8e..a713744 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -1131,6 +1131,253 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = {
 	},
 };
 
+/* VPU Clock */
+
+static u32 mux_table_vpu[] = {0, 1, 2, 3};
+static const char * const gxbb_vpu_parent_names[] = {
+	"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
+};
+
+static struct clk_mux gxbb_vpu_0_sel = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.mask = 0x3,
+	.shift = 9,
+	.lock = &clk_lock,
+	.table = mux_table_vpu,
+	.hw.init = &(struct clk_init_data){
+		.name = "vpu_0_sel",
+		.ops = &clk_mux_ops,
+		/*
+		 * bits 9:10 selects from 4 possible parents:
+		 * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
+		 */
+		.parent_names = gxbb_vpu_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vpu_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_divider gxbb_vpu_0_div = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.shift = 0,
+	.width = 7,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vpu_0_div",
+		.ops = &clk_divider_ops,
+		.parent_names = (const char *[]){ "vpu_0_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_gate gxbb_vpu_0 = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.bit_idx = 8,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data) {
+		.name = "vpu_0",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "vpu_0_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_mux gxbb_vpu_1_sel = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.mask = 0x3,
+	.shift = 25,
+	.lock = &clk_lock,
+	.table = mux_table_vpu,
+	.hw.init = &(struct clk_init_data){
+		.name = "vpu_1_sel",
+		.ops = &clk_mux_ops,
+		/*
+		 * bits 25:26 selects from 4 possible parents:
+		 * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
+		 */
+		.parent_names = gxbb_vpu_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vpu_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_divider gxbb_vpu_1_div = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.shift = 16,
+	.width = 7,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vpu_1_div",
+		.ops = &clk_divider_ops,
+		.parent_names = (const char *[]){ "vpu_1_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_gate gxbb_vpu_1 = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.bit_idx = 24,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data) {
+		.name = "vpu_1",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "vpu_1_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_mux gxbb_vpu = {
+	.reg = (void *)HHI_VPU_CLK_CNTL,
+	.mask = 1,
+	.shift = 31,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vpu",
+		.ops = &clk_mux_ops,
+		/*
+		 * bit 31 selects from 2 possible parents:
+		 * vpu_0 or vpu_1
+		 */
+		.parent_names = (const char *[]){ "vpu_0", "vpu_1" },
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+/* VAPB Clock */
+
+static u32 mux_table_vapb[] = {0, 1, 2, 3};
+static const char * const gxbb_vapb_parent_names[] = {
+	"fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7"
+};
+
+static struct clk_mux gxbb_vapb_0_sel = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.mask = 0x3,
+	.shift = 9,
+	.lock = &clk_lock,
+	.table = mux_table_vapb,
+	.hw.init = &(struct clk_init_data){
+		.name = "vapb_0_sel",
+		.ops = &clk_mux_ops,
+		/*
+		 * bits 9:10 selects from 4 possible parents:
+		 * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
+		 */
+		.parent_names = gxbb_vapb_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vapb_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_divider gxbb_vapb_0_div = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.shift = 0,
+	.width = 7,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vapb_0_div",
+		.ops = &clk_divider_ops,
+		.parent_names = (const char *[]){ "vapb_0_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_gate gxbb_vapb_0 = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.bit_idx = 8,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data) {
+		.name = "vapb_0",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "vapb_0_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_mux gxbb_vapb_1_sel = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.mask = 0x3,
+	.shift = 25,
+	.lock = &clk_lock,
+	.table = mux_table_vapb,
+	.hw.init = &(struct clk_init_data){
+		.name = "vapb_1_sel",
+		.ops = &clk_mux_ops,
+		/*
+		 * bits 25:26 selects from 4 possible parents:
+		 * fclk_div4, fclk_div3, fclk_div5, fclk_div7,
+		 */
+		.parent_names = gxbb_vapb_parent_names,
+		.num_parents = ARRAY_SIZE(gxbb_vapb_parent_names),
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_divider gxbb_vapb_1_div = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.shift = 16,
+	.width = 7,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vapb_1_div",
+		.ops = &clk_divider_ops,
+		.parent_names = (const char *[]){ "vapb_1_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_gate gxbb_vapb_1 = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.bit_idx = 24,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data) {
+		.name = "vapb_1",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "vapb_1_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_mux gxbb_vapb_sel = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.mask = 1,
+	.shift = 31,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "vapb_sel",
+		.ops = &clk_mux_ops,
+		/*
+		 * bit 31 selects from 2 possible parents:
+		 * vapb_0 or vapb_1
+		 */
+		.parent_names = (const char *[]){ "vapb_0", "vapb_1" },
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
+static struct clk_gate gxbb_vapb = {
+	.reg = (void *)HHI_VAPBCLK_CNTL,
+	.bit_idx = 30,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data) {
+		.name = "vapb",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "vapb_sel" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+	},
+};
+
 /* Everything Else (EE) domain gates */
 static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
 static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
@@ -1349,6 +1596,21 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
 		[CLKID_SD_EMMC_C_CLK0_SEL]  = &gxbb_sd_emmc_c_clk0_sel.hw,
 		[CLKID_SD_EMMC_C_CLK0_DIV]  = &gxbb_sd_emmc_c_clk0_div.hw,
 		[CLKID_SD_EMMC_C_CLK0]	    = &gxbb_sd_emmc_c_clk0.hw,
+		[CLKID_VPU_0_SEL]	    = &gxbb_vpu_0_sel.hw,
+		[CLKID_VPU_0_DIV]	    = &gxbb_vpu_0_div.hw,
+		[CLKID_VPU_0]		    = &gxbb_vpu_0.hw,
+		[CLKID_VPU_1_SEL]	    = &gxbb_vpu_1_sel.hw,
+		[CLKID_VPU_1_DIV]	    = &gxbb_vpu_1_div.hw,
+		[CLKID_VPU_1]		    = &gxbb_vpu_1.hw,
+		[CLKID_VPU]		    = &gxbb_vpu.hw,
+		[CLKID_VAPB_0_SEL]	    = &gxbb_vapb_0_sel.hw,
+		[CLKID_VAPB_0_DIV]	    = &gxbb_vapb_0_div.hw,
+		[CLKID_VAPB_0]		    = &gxbb_vapb_0.hw,
+		[CLKID_VAPB_1_SEL]	    = &gxbb_vapb_1_sel.hw,
+		[CLKID_VAPB_1_DIV]	    = &gxbb_vapb_1_div.hw,
+		[CLKID_VAPB_1]		    = &gxbb_vapb_1.hw,
+		[CLKID_VAPB_SEL]	    = &gxbb_vapb_sel.hw,
+		[CLKID_VAPB]		    = &gxbb_vapb.hw,
 		[NR_CLKS]		    = NULL,
 	},
 	.num = NR_CLKS,
@@ -1481,6 +1743,21 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
 		[CLKID_SD_EMMC_C_CLK0_SEL]  = &gxbb_sd_emmc_c_clk0_sel.hw,
 		[CLKID_SD_EMMC_C_CLK0_DIV]  = &gxbb_sd_emmc_c_clk0_div.hw,
 		[CLKID_SD_EMMC_C_CLK0]	    = &gxbb_sd_emmc_c_clk0.hw,
+		[CLKID_VPU_0_SEL]	    = &gxbb_vpu_0_sel.hw,
+		[CLKID_VPU_0_DIV]	    = &gxbb_vpu_0_div.hw,
+		[CLKID_VPU_0]		    = &gxbb_vpu_0.hw,
+		[CLKID_VPU_1_SEL]	    = &gxbb_vpu_1_sel.hw,
+		[CLKID_VPU_1_DIV]	    = &gxbb_vpu_1_div.hw,
+		[CLKID_VPU_1]		    = &gxbb_vpu_1.hw,
+		[CLKID_VPU]		    = &gxbb_vpu.hw,
+		[CLKID_VAPB_0_SEL]	    = &gxbb_vapb_0_sel.hw,
+		[CLKID_VAPB_0_DIV]	    = &gxbb_vapb_0_div.hw,
+		[CLKID_VAPB_0]		    = &gxbb_vapb_0.hw,
+		[CLKID_VAPB_1_SEL]	    = &gxbb_vapb_1_sel.hw,
+		[CLKID_VAPB_1_DIV]	    = &gxbb_vapb_1_div.hw,
+		[CLKID_VAPB_1]		    = &gxbb_vapb_1.hw,
+		[CLKID_VAPB_SEL]	    = &gxbb_vapb_sel.hw,
+		[CLKID_VAPB]		    = &gxbb_vapb.hw,
 		[NR_CLKS]		    = NULL,
 	},
 	.num = NR_CLKS,
@@ -1600,6 +1877,11 @@ static struct clk_gate *const gxbb_clk_gates[] = {
 	&gxbb_sd_emmc_a_clk0,
 	&gxbb_sd_emmc_b_clk0,
 	&gxbb_sd_emmc_c_clk0,
+	&gxbb_vpu_0,
+	&gxbb_vpu_1,
+	&gxbb_vapb_0,
+	&gxbb_vapb_1,
+	&gxbb_vapb,
 };
 
 static struct clk_mux *const gxbb_clk_muxes[] = {
@@ -1615,6 +1897,12 @@ static struct clk_mux *const gxbb_clk_muxes[] = {
 	&gxbb_sd_emmc_a_clk0_sel,
 	&gxbb_sd_emmc_b_clk0_sel,
 	&gxbb_sd_emmc_c_clk0_sel,
+	&gxbb_vpu_0_sel,
+	&gxbb_vpu_1_sel,
+	&gxbb_vpu,
+	&gxbb_vapb_0_sel,
+	&gxbb_vapb_1_sel,
+	&gxbb_vapb_sel,
 };
 
 static struct clk_divider *const gxbb_clk_dividers[] = {
@@ -1627,6 +1915,10 @@ static struct clk_divider *const gxbb_clk_dividers[] = {
 	&gxbb_sd_emmc_a_clk0_div,
 	&gxbb_sd_emmc_b_clk0_div,
 	&gxbb_sd_emmc_c_clk0_div,
+	&gxbb_vpu_0_div,
+	&gxbb_vpu_1_div,
+	&gxbb_vapb_0_div,
+	&gxbb_vapb_1_div,
 };
 
 static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
-- 
2.7.4

